# -*- coding: utf-8 -*-
#
#  IPTV Tools
#
#  $Id$
#
#
###################################################
# LOCAL import
###################################################
from Plugins.Extensions.IPTVPlayer.components.iptvplayerinit import TranslateTXT as _
from Plugins.Extensions.IPTVPlayer.p2p3.UrlLib import urllib2_urlopen, urllib2_Request, urllib2_URLError, urllib2_HTTPError
from Plugins.Extensions.IPTVPlayer.p2p3.manipulateStrings import strDecode, ensure_str
###################################################

###################################################
# FOREIGN import
###################################################
from Components.config import config
from Tools.Directories import resolveFilename, fileExists, SCOPE_PLUGINS, SCOPE_CONFIG
from enigma import eConsoleAppContainer
from Components.Language import language
from time import time
from urllib.request import urlopen
import traceback
import re
import sys
import os
import stat
import codecs
import datetime
from functools import cmp_to_key
import socket

# SERVER_DOMAINS = {'vline': 'http://iptvplayer.vline.pl/', 'gitlab': 'http://zadmario.gitlab.io/', 'private': 'http://www.e2iplayer.gitlab.io/'}
# SERVER_UPDATE_PATH = {'vline': 'download/update2/', 'gitlab': 'update2/', 'private': 'update2/'}


def UsePyCurl():
    return config.plugins.iptvplayer.usepycurl.value


def GetIconsHash():
    iconsHashFile = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/PlayerSelector/hash.txt')
    sts, data = ReadTextFile(iconsHashFile)
    if sts:
        return data.strip()
    else:
        return ''


def SetIconsHash(value):
    iconsHashFile = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/PlayerSelector/hash.txt')
    return WriteTextFile(iconsHashFile, value)


def GetGraphicsHash():
    graphicsHashFile = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/hash.txt')
    sts, data = ReadTextFile(graphicsHashFile)
    if sts:
        return data.strip()
    else:
        return ''


def SetGraphicsHash(value):
    graphicsHashFile = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/hash.txt')
    return WriteTextFile(graphicsHashFile, value)

###################################################


def DaysInMonth(dt):
    return (datetime.date(dt.year + (dt.month / 12), (dt.month % 12) + 1, 1) - dt).days + dt.day - 1


def NextMonth(dt):
    return (dt.replace(day=28) + datetime.timedelta(days=4)).replace(day=1)


def PrevMonth(dt):
    return (dt.replace(day=1) - datetime.timedelta(days=1)).replace(day=1)


def NextDay(dt):
    return (dt + datetime.timedelta(days=1))


def PrevDay(dt):
    return (dt - datetime.timedelta(days=1))

###################################################


def GetNice(pid=None):
    nice = 0
    if None is pid:
        pid = 'self'
    filePath = '/proc/%s/stat' % pid
    try:
        with open(filePath, 'r') as f:
            data = f.read()
            data = data.split(' ')[19]
            nice = int(data)
    except Exception:
        printExc()
    return nice


def E2PrioFix(cmd, factor=2):
    if '/duk' not in cmd:  # and config.plugins.iptvplayer.plarform.value in ('mipsel', 'armv7', 'armv5t'):
        return 'nice -n %d %s' % (GetNice() + factor, cmd)
    else:
        return cmd


def GetDefaultLang(full=False):
    if full:
        try:
            defaultLanguage = language.getActiveLanguage()
        except Exception:
            printExc()
            defaultLanguage = 'en_EN'
    else:
        try:
            defaultLanguage = language.getActiveLanguage().split('_')[0]
        except Exception:
            printExc()
            defaultLanguage = 'en'
    return defaultLanguage


def GetPolishSubEncoding(filePath):
    encoding = 'utf-8'
    # Method provided by @areq: http://forum.dvhk.to/showpost.php?p=5367956&postcount=5331
    try:
        f = open(filePath)
        sub = f.read()
        f.close()
        iso = 0
        for i in (161, 166, 172, 177, 182, 188):
            iso += sub.count(chr(i))
        win = 0
        for i in (140, 143, 156, 159, 165, 185):
            win += sub.count(chr(i))
        utf = 0
        for i in (195, 196, 197):
            utf += sub.count(chr(i))
        if win > utf and win > iso:
            encoding = "CP1250"
        elif utf > iso and utf > win:
            encoding = "utf-8"
        else:
            encoding = "iso-8859-2"
        printDBG("IPTVExtMoviePlayer _getEncoding iso[%d] win[%d ] utf[%d] -> [%s]" % (iso, win, utf, encoding))
    except Exception:
        printExc()
    return encoding


def MapUcharEncoding(encoding):
    ENCODING_MAP = {'X-MAC-CYRILLIC': "MAC-CYRILLIC", "ASCII": "UTF-8"}
    printDBG("MapUcharEncoding in encoding[%s]" % encoding)
    try:
        encoding = ENCODING_MAP.get(encoding.strip().upper(), encoding.strip())
    except Exception:
        printExc()
    printDBG("MapUcharEncoding out encoding[%s]" % encoding)
    return encoding


class eConnectCallbackObj:
    OBJ_ID = 0
    OBJ_NUM = 0

    def __init__(self, obj=None, connectHandler=None):
        eConnectCallbackObj.OBJ_ID += 1
        eConnectCallbackObj.OBJ_NUM += 1
        self.objID = eConnectCallbackObj.OBJ_ID
        printDBG("eConnectCallbackObj.__init__ objID[%d] OBJ_NUM[%d]" % (self.objID, eConnectCallbackObj.OBJ_NUM))
        self.connectHandler = connectHandler
        self.obj = obj

    def __del__(self):
        eConnectCallbackObj.OBJ_NUM -= 1
        printDBG("eConnectCallbackObj.__del__ objID[%d] OBJ_NUM[%d] " % (self.objID, eConnectCallbackObj.OBJ_NUM))
        try:
            if 'connect' not in dir(self.obj):
                if 'get' in dir(self.obj):
                    self.obj.get().remove(self.connectHandler)
                else:
                    self.obj.remove(self.connectHandler)
            else:
                del self.connectHandler
        except Exception:
            printExc()
        self.connectHandler = None
        self.obj = None


def eConnectCallback(obj, callbackFun, withExcept=False):
    try:
        if 'connect' in dir(obj):
            return eConnectCallbackObj(obj, obj.connect(callbackFun))
        else:
            if 'get' in dir(obj):
                obj.get().append(callbackFun)
            else:
                obj.append(callbackFun)
            return eConnectCallbackObj(obj, callbackFun)
    except Exception:
        printExc("eConnectCallback")
    return eConnectCallbackObj()


class iptv_system:
    '''
    Calling os.system is not recommended, it may fail due to lack of memory,
    please use iptv_system instead, this should be used as follow:
    self.handle = iptv_system("cmd", callBackFun)
    there is need to have reference to the obj created by iptv_system,
    without reference to return obj behavior is undefined

    iptv_system must be used only inside MainThread context, please see
    iptv_execute class from asynccall module which is dedicated to be
    used inside other threads
    '''

    def __init__(self, cmd, callBackFun=None):
        printDBG("iptv_system.__init__ cmd [%s]" % cmd)
        self.callBackFun = callBackFun
        self.cmd = cmd

        self.console = eConsoleAppContainer()
        if None is not self.callBackFun:
            self.console_appClosed_conn = eConnectCallback(self.console.appClosed, self._cmdFinished)
            self.console_stdoutAvail_conn = eConnectCallback(self.console.stdoutAvail, self._dataAvail)
            self.outData = ""
        if hasattr(self.console, "setNice"):
            self.console.setNice(GetNice() + 2)
            self.console.execute(cmd)
        else:
            self.console.execute(E2PrioFix(cmd))

    def terminate(self, doCallBackFun=False):
        self.kill(doCallBackFun)

    def kill(self, doCallBackFun=False):
        if None is not self.console:
            if None is not self.callBackFun:
                self.console_appClosed_conn = None
                self.console_stdoutAvail_conn = None
            else:
                doCallBackFun = False
            self.console.sendCtrlC()
            self.console = None
            if doCallBackFun:
                self.callBackFun(-1, self.outData)
                self.callBackFun = None

    def _dataAvail(self, data):
        if None is not data:
            self.outData += strDecode(data)

    def _cmdFinished(self, code):
        printDBG("iptv_system._cmdFinished cmd[%s] code[%r]" % (self.cmd, code))
        self.console_appClosed_conn = None
        self.console_stdoutAvail_conn = None
        self.console = None
        self.callBackFun(code, self.outData)
        self.callBackFun = None

    def __del__(self):
        printDBG("iptv_system.__del__ cmd[%s]" % self.cmd)


def IsHttpsCertValidationEnabled():
    return config.plugins.iptvplayer.httpssslcertvalidation.value


def GetAvailableIconSize(checkAll=True):
    iconSizes = [config.plugins.iptvplayer.IconsSize.value]
    if checkAll:
        iconSizes.extend(['135', '120', '100'])
    confirmedIconSize = 0
    for size in iconSizes:
        try:
            file = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/PlayerSelector/marker{0}.png').format(int(size) + 45)
            if fileExists(file):
                confirmedIconSize = int(size)
                break
        except Exception:
            printExc()
    return confirmedIconSize

#############################################################
# returns the directory path where specified resources are
# stored, in the future, it can be changed in the config
#############################################################


def GetLogoDir(file=''):
    return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/logos/') + file


def GetPyScriptCmd(name):
    cmd = ''
    baseName = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/scripts/') + name
    if fileExists(baseName + '.py'):
        baseName += '.py'
    elif fileExists(baseName + '.pyc'):
        baseName += '.pyc'
    if baseName != '':
        for item in ['python']:
            pyPath = Which(item)
            if '' != pyPath:
                cmd = '%s %s' % (pyPath, baseName)
                break
    return cmd


def GetJSScriptFile(file):
    return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/jsscripts/') + file


gE2iPlayerTempCookieDir = None


def SetTmpCookieDir():
    global gE2iPlayerTempCookieDir
    gE2iPlayerTempCookieDir = '/tmp/e2iplayer_cookies/'
    mkdirs(gE2iPlayerTempCookieDir)


def ClearTmpCookieDir():
    global gE2iPlayerTempCookieDir
    if gE2iPlayerTempCookieDir is not None:
        try:
            for fileName in os.listdir(gE2iPlayerTempCookieDir):
                rm(os.path.join(gE2iPlayerTempCookieDir, fileName))
        except Exception:
            printExc()

    gE2iPlayerTempCookieDir = None


def TestTmpCookieDir():
    path = GetCookieDir(forceFromConfig=True)
    if not os.path.isdir(path):
        mkdirs(path, True)
    with open(path + ".rw_test", 'w') as f:
        f.write("test")


def GetCookieDir(file='', forceFromConfig=False):
    if gE2iPlayerTempCookieDir is None or forceFromConfig:
        cookieDir = os.path.join(config.plugins.iptvplayer.SciezkaCache.value, 'cookies/')
    else:
        cookieDir = gE2iPlayerTempCookieDir
    try:
        if not os.path.isdir(cookieDir):
            mkdirs(cookieDir)
    except Exception:
        printExc()
    return cookieDir + file


###########################
gE2iPlayerTempJSCache = None


def SetTmpJSCacheDir():
    global gE2iPlayerTempJSCache
    gE2iPlayerTempJSCache = '/tmp/e2iplayer_js_cache/'
    mkdirs(gE2iPlayerTempJSCache)


def ClearTmpJSCacheDir():
    global gE2iPlayerTempJSCache
    if gE2iPlayerTempJSCache is not None:
        try:
            for fileName in os.listdir(gE2iPlayerTempJSCache):  # file is native p2 function renamed for clarity
                rm(os.path.join(gE2iPlayerTempJSCache, fileName))
        except Exception:
            printExc()
    gE2iPlayerTempJSCache = None


def TestTmpJSCacheDir():
    path = GetJSCacheDir(forceFromConfig=True)
    if not os.path.isdir(path):
        mkdirs(path, True)
    with open(path + ".rw_test", 'w') as f:
        f.write("test")


def GetJSCacheDir(fileName='', forceFromConfig=False):
    if gE2iPlayerTempJSCache is None or forceFromConfig:
        cookieDir = os.path.join(config.plugins.iptvplayer.SciezkaCache.value, 'JSCache/')
    else:
        cookieDir = gE2iPlayerTempJSCache
    try:
        if not os.path.isdir(cookieDir):
            mkdirs(cookieDir)
    except Exception:
        printExc()
    return os.path.join(cookieDir, fileName)
##############################


def GetTmpDir(fileName=''):
    path = config.plugins.iptvplayer.NaszaTMP.value
    path = path.replace('//', '/')
    mkdirs(path)
    return os.path.join(path, fileName)


# def GetE2iPlayerRootfsDir(fileName=''):
#    return os.path.join('/iptvplayer_rootfs', fileName)


def GetE2iPlayerVKLayoutDir(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/vk/'), fileName)


def CreateTmpFile(filename, data=''):
    sts = False
    filePath = GetTmpDir(filename)
    try:
        with open(filePath, 'w') as f:
            f.write(data)
            sts = True
    except Exception:
        printExc()
    return sts, filePath


def GetCacheSubDir(dirName, fileName=''):
    path = os.path.join(config.plugins.iptvplayer.SciezkaCache.value, dirName)
    mkdirs(path)
    return os.path.join(path, fileName)


def GetSearchHistoryDir(fileName=''):
    return GetCacheSubDir('SearchHistory', fileName)


def GetFavouritesDir(fileName=''):
    return GetCacheSubDir('IPTVFavourites', fileName)


def GetSubtitlesDir(fileName=''):
    return GetCacheSubDir('Subtitles', fileName)


def GetMovieMetaDataDir(fileName=''):
    return GetCacheSubDir('MovieMetaData', fileName)


def GetIPTVDMImgDir(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/'), fileName)


def GetIconDir(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/'), fileName)


def GetPluginDir(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/'), fileName)


def GetExtensionsDir(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/'), fileName)


def GetSkinsDir(path=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/skins/'), path)


def GetPlayerSkinDir(path=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/playerskins/'), path)


def GetConfigDir(path=''):
    return resolveFilename(SCOPE_CONFIG, path)


def IsExecutable(fpath):
    try:
        if '' != Which(fpath):
            return True
    except Exception:
        printExc()
    return False


def Which(program):
    try:
        def is_exe(fpath):
            return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
        fpath, fname = os.path.split(program)
        if fpath:
            if is_exe(program):
                return program
        else:
            # pathTab = ['/iptvplayer_rootfs/bin', '/iptvplayer_rootfs/usr/bin', '/iptvplayer_rootfs/sbin', '/iptvplayer_rootfs/usr/sbin']
            pathTab = []
            pathTab.extend(os.environ["PATH"].split(os.pathsep))
            for path in pathTab:
                path = path.strip('"')
                exe_file = os.path.join(path, program)
                if is_exe(exe_file):
                    return exe_file
    except Exception:
        printExc()
    return ''
#############################################################
# class used to auto-select one link when video has several
# links with different qualities
#############################################################


class CSelOneLink():

    def __init__(self, listOfLinks, getQualiyFun, maxRes):
        self.listOfLinks = listOfLinks
        self.getQualiyFun = getQualiyFun
        self.maxRes = maxRes

    def _cmpLinks(self, item1, item2):
        val1 = self.getQualiyFun(item1)
        val2 = self.getQualiyFun(item2)

        if val1 is None or val2 is None:
            printDBG('iptvtools.CSelOneLink()_cmpLinks <host>__getLinkQuality() returned None value(s) which is an error(val1=%s, val2=%s)\n\t CORRECT <host>!!!' % (str(val1), str(val2)))
            ret = 0
        elif val1 < val2:
            ret = -1
        elif val1 > val2:
            ret = 1
        else:
            ret = 0
        return ret

    def _cmpLinksBest(self, item1, item2):
        return -1 * self._cmpLinks(item1, item2)

    def getBestSortedList(self):
        printDBG('getBestSortedList')
        sortList = self.listOfLinks[::-1]
        sortList.sort(key=cmp_to_key(self._cmpLinksBest))
        retList = []
        tmpList = []
        for item in sortList:
            linkRes = self.getQualiyFun(item)
            if linkRes <= self.maxRes:
                retList.append(item)
            else:
                tmpList.insert(0, item)
        retList.extend(tmpList)
        return retList

    def getSortedLinks(self, defaultFirst=True):
        printDBG('getSortedLinks defaultFirst[%r]' % defaultFirst)
        sortList = self.listOfLinks[::-1]
        sortList.sort(key=cmp_to_key(self._cmpLinks))
        if len(self.listOfLinks) < 2 or None is self.maxRes:
            return self.listOfLinks

        if defaultFirst:
            # split links to two groups
            # first gorup will meet maxRes
            # second group not
            group1 = []
            group2 = []
            for idx in range(len(self.listOfLinks)):
                if self.getQualiyFun(self.listOfLinks[idx]) <= self.maxRes:
                    group1.append(self.listOfLinks[idx])
                else:
                    group2.append(self.listOfLinks[idx])
            group1.sort(key=cmp_to_key(self._cmpLinks))
            group2.sort(key=cmp_to_key(self._cmpLinks))
            group1.reverse()
            group1.extend(group2)
            return group1

        defIdx = -1
        for idx in range(len(sortList)):
            linkRes = self.getQualiyFun(sortList[idx])
            printDBG("=============== getOneLink [%r] res[%r] maxRes[%r]" % (sortList[idx], linkRes, self.maxRes))
            if linkRes <= self.maxRes:
                defIdx = idx
                printDBG('getOneLink use format %d/%d' % (linkRes, self.maxRes))

        if defaultFirst and -1 < defIdx:
            item = sortList[defIdx]
            del sortList[defIdx]
            sortList.insert(0, item)
        return sortList

    def getOneLink(self):
        printDBG('getOneLink start')
        tab = self.getSortedLinks()
        if len(tab) == 0:
            return tab
        return [tab[0]]
# end CSelOneLink

#############################################################
# prints debugs on screen or to the file
#############################################################
# debugs


def getDebugMode():
    DBG = ''
    try:
        from Components.config import config
        DBG = config.plugins.iptvplayer.debugprint.value
    except Exception:
        file = open(resolveFilename(SCOPE_CONFIG, "settings"))
        for line in file:
            if line.startswith('config.plugins.iptvplayer.debugprint='):
                DBG = line.split("=")[1].strip()
                break
    return DBG


def printDBG(DBGtxt, writeMode='a'):
    DBG = getDebugMode()
    if DBG == '':
        return
    elif DBG == 'console':
        print(DBGtxt)
    else:
        if DBG == 'debugfile':
            DBGfile = '/hdd/iptv.dbg'  # backward compatibility
        else:
            DBGfile = DBG
        try:
            f = open(DBGfile, writeMode)
            f.write(str(DBGtxt) + '\n')
            f.close
        except Exception:
            print("======================EXC printDBG======================")
            print("printDBG(I): %s" % traceback.format_exc())
            print("========================================================")
            try:
                msg = '%s' % traceback.format_exc()
                f = open(DBGfile, writeMode)
                f.write(str(DBGtxt) + '\n')
                f.close
            except Exception:
                print("======================EXC printDBG======================")
                print("printDBG(II): %s" % traceback.format_exc())
                print("========================================================")


#####################################################
# get host list based on files in /hosts folder
#####################################################
g_cacheHostsFromList = None
g_cacheHostsFromFolder = None
g_cachePluginFolder = None


def __isHostNameValid(hostName):
    BLOCKED_MARKER = '_blocked_'
    if len(hostName) > 4 and BLOCKED_MARKER not in hostName and hostName.startswith("host"):
        return True
    return False


def getHostsPath(fileName=''):
    return os.path.join(resolveFilename(SCOPE_PLUGINS), 'Extensions/IPTVPlayer/hosts/', fileName)


def GetHostsFromList(useCache=True):
    global g_cacheHostsFromList
    if useCache and g_cacheHostsFromList is not None and len(g_cacheHostsFromList) > 0:
        printDBG('iptvtools.GetHostsFromList returns cached list (%s)' % str(g_cacheHostsFromList))
        return list(g_cacheHostsFromList)

    lhosts = []
    try:
        sts, data = ReadTextFile(getHostsPath('list.txt'))
        if sts:
            data = data.split('\n')
            for item in data:
                line = item.strip()
                if __isHostNameValid(line):
                    lhosts.append(line[4:])
                    printDBG('getHostsList add host from list.txt hostName: "%s"' % line[4:])
    except Exception:
        printExc()

    g_cacheHostsFromList = lhosts
    printDBG(str(g_cacheHostsFromList))
    return lhosts


def GetHostsFromFolder(useCache=True):
    global g_cacheHostsFromFolder
    if useCache and g_cacheHostsFromFolder is not None and len(g_cacheHostsFromFolder) > 0:
        printDBG('iptvtools.GetHostsFromFolder returns cached list (%s)' % str(g_cacheHostsFromFolder))
        return g_cacheHostsFromFolder

    lhosts = []
    try:
        fileList = os.listdir(getHostsPath())
        printDBG('\t len(fileList)=%s' % len(fileList))
        for wholeFileName in fileList:
            # separate file name and file extension
            fileName, fileExt = os.path.splitext(wholeFileName)
            nameLen = len(fileName)
            if fileExt in ['.pyo', '.pyc', '.py'] and nameLen > 4 and __isHostNameValid(fileName):
                if fileName[4:] not in lhosts:
                    lhosts.append(fileName[4:])
                    printDBG('getHostsList add host with fileName: "%s"' % fileName[4:])
        printDBG('iptvtools.getHostsList end')
        lhosts.sort()
    except Exception:
        printDBG('iptvtools.GetHostsList EXCEPTION')

    g_cacheHostsFromFolder = lhosts
    return lhosts


def GetHostsList(fromList=True, fromHostFolder=True, useCache=True):
    lhosts = []
    if fromHostFolder:
        printDBG('iptvtools.getHostsList(fromHostFolder)')
        lhosts = GetHostsFromFolder(useCache)

    # when new option to remove not enabled host is enabled
    # on list should be also host which are not normally in
    # the folder, so we will read first predefined list
    if fromList:
        printDBG('iptvtools.getHostsList(fromList)')
        tmp = GetHostsFromList(useCache)
        for host in tmp:
            if host not in lhosts:
                lhosts.append(host)

    return lhosts


def GetHostsAliases():
    from Plugins.Extensions.IPTVPlayer.libs.e2ijson import loads as json_loads
    ret = {}
    try:
        HOST_PATH = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/hosts/')
        sts, data = ReadTextFile(os.path.join(HOST_PATH, 'aliases.txt'))
        if sts:
            data = data.replace("'", '"')
            data = json_loads(data)
            if isinstance(data, dict):
                ret = data
    except Exception:
        printExc()
    return ret


def GetEnabledHostsList():
    hostsList = GetHostsList(fromList=True, fromHostFolder=True)
    enabledHostsList = []
    for hostName in hostsList:
        if IsHostEnabled(hostName):
            enabledHostsList.append(hostName)
    return enabledHostsList


def SortHostsList(hostsList):
    hostsList = list(hostsList)
    hostsOrderList = GetHostsOrderList()
    sortedList = []
    for item in hostsOrderList:
        if item in hostsList:
            sortedList.append(item)
            hostsList.remove(item)
    sortedList.extend(hostsList)
    return sortedList


def SaveHostsOrderList(list, fileName="iptvplayerhostsorder"):
    printDBG('SaveHostsOrderList begin')
    fname = GetConfigDir(fileName)
    try:
        f = open(fname, 'w')
        for item in list:
            f.write(item + '\n')
        f.close()
    except Exception:
        printExc()


def GetHostsOrderList(fileName="iptvplayerhostsorder"):
    printDBG('GetHostsOrderList begin')
    fname = GetConfigDir(fileName)
    list = []
    try:
        if fileExists(fname):
            with open(fname, 'r') as f:
                content = f.readlines()
            for item in content:
                item = item.strip()
                if len(item):
                    list.append(item)
        else:
            printDBG('GetHostsOrderList file[%s] not exists' % fname)
    except Exception:
        printExc()
    return list


def GetSkinsList():
    printDBG('getSkinsList begin')
    skins = []
    SKINS_PATH = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/skins/')
    fileList = os.listdir(SKINS_PATH)
    for filename in fileList:
        skins.append((filename, filename))
    skins.sort()
    skins.insert(0, ("", _("Default")))
    printDBG('getSkinsList end')
    return skins


def IsHostEnabled(hostName):
    hostEnabled = False
    try:
        if getattr(config.plugins.iptvplayer, 'host' + hostName).value:
            hostEnabled = True
    except Exception:
        hostEnabled = False
    return hostEnabled

##############################################################
# check if we have enough free space
# if required == None return free space instead of comparing
# default unit = MB
##############################################################


def FreeSpace(katalog, requiredSpace, unitDiv=1024 * 1024):
    try:
        s = os.statvfs(katalog)
        freeSpace = s.f_bfree * s.f_frsize  # all free space
        if 512 > (freeSpace / (1024 * 1024)):
            freeSpace = s.f_bavail * s.f_frsize
        freeSpace = freeSpace / unitDiv
    except Exception:
        printExc()
        freeSpace = -1
    printDBG("FreeSpace freeSpace[%s] requiredSpace[%s] unitDiv[%s]" % (freeSpace, requiredSpace, unitDiv))
    if None is requiredSpace:
        return freeSpace
    else:
        if freeSpace >= requiredSpace:
            return True
        else:
            return False


def IsValidFileName(name, NAME_MAX=255):
    prohibited_characters = ['/', "\000", '\\', ':', '*', '<', '>', '|', '"']
    if isinstance(name, str) and (1 <= len(name) <= NAME_MAX):
        for it in name:
            if it in prohibited_characters:
                return False
        return True
    return False


def RemoveDisallowedFilenameChars(name, replacment='.'):
    prohibited_characters = ['/', "\000", '\\', ':', '*', '<', '>', '|', '"']
    for item in prohibited_characters:
        name = name.replace(item, replacment).replace(replacment + replacment, replacment)
    return name


def touch(fname, times=None):
    try:
        with open(fname, 'a'):
            os.utime(fname, times)
        return True
    except Exception:
        printExc()
        return False


def mkdir(newdir):
    """ Wrapper for the os.mkdir function
        returns status instead of raising exception
    """
    try:
        os.mkdir(newdir)
        sts = True
        msg = 'Katalog "%s" został utworzony poprawnie.' % newdir
    except Exception:
        sts = False
        msg = 'Katalog "%s" nie może zostać utworzony.' % newdir
        printExc()
    return sts, msg


def mkdirs(newdir, raiseException=False):
    """ Create a directory and all parent folders.
        Features:
        - parent directories will be created
        - if directory already exists, then do nothing
        - if there is another filsystem object with the same name, raise an exception
    """
    printDBG('mkdirs: "%s"' % newdir)
    try:
        if os.path.isdir(newdir):
            pass
        elif os.path.isfile(newdir):
            raise OSError("cannot create directory, file already exists: '%s'" % newdir)
        else:
            head, tail = os.path.split(newdir)
            if head and not os.path.isdir(head) and not os.path.ismount(head) and not os.path.islink(head):
                mkdirs(head)
            if tail:
                os.mkdir(newdir)
        return True
    except Exception as e:
        printDBG('Exception mkdirs["%s"]' % e)
        if raiseException:
            raise e
    return False


def rm(fullname):
    try:
        if os.path.exists(fullname):
            os.remove(fullname)
        return True
    except Exception:
        printExc()
    return False


def rmtree(path, ignore_errors=False, onerror=None):
    """Recursively delete a directory tree.
    If ignore_errors is set, errors are ignored; otherwise, if onerror
    is set, it is called to handle the error with arguments (func,
    path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
    path is the argument to that function that caused it to fail; and
    exc_info is a tuple returned by sys.exc_info(). If ignore_errors
    is false and onerror is None, an exception is raised.
    """
    if ignore_errors:
        def onerror(*args):
            pass
    elif onerror is None:
        def onerror(*args):
            raise
    try:
        if os.path.islink(path):
            # symlinks to directories are forbidden, see bug #1669
            raise OSError("Cannot call rmtree on a symbolic link")
    except OSError:
        onerror(os.path.islink, path)
        # can't continue even if onerror hook returns
        return
    names = []
    try:
        names = os.listdir(path)
    except os.error as err:
        onerror(os.listdir, path)
    for name in names:
        fullname = os.path.join(path, name)
        try:
            mode = os.lstat(fullname).st_mode
        except os.error:
            mode = 0
        if stat.S_ISDIR(mode):
            rmtree(fullname, ignore_errors, onerror)
        else:
            try:
                os.remove(fullname)
            except os.error as err:
                onerror(os.remove, fullname)
    try:
        os.rmdir(path)
    except os.error:
        onerror(os.rmdir, path)


def GetFileSize(filepath):
    try:
        return os.stat(filepath).st_size
    except Exception:
        return -1


def DownloadFile(url, filePath):
    printDBG('DownloadFile [%s] from [%s]' % (filePath, url))
    try:
        downloadFile = urlopen(url)
        output = open(filePath, 'wb')
        output.write(downloadFile.read())
        output.close()
        try:
            iptv_system('sync')
        except Exception:
            printExc('DownloadFile sync exception')
        return True
    except Exception:
        try:
            if os.path.exists(filePath):
                os.remove(filePath)
            return False
        except Exception:
            printExc()
            return False

########################################################
#                     For icon manager
########################################################


def GetLastDirNameFromPath(path):
    path = os.path.normcase(path)
    if path[-1] == '/':
        path = path[:-1]
    dirName = path.split('/')[-1]
    return dirName


def GetIconDirBaseName():
    return '.iptvplayer_icons_'


def CheckIconName(name):
    # check if name is correct
    if 36 == len(name) and '.jpg' == name[-4:]:
        try:
            tmp = int(name[:-4], 16)
            return True
        except Exception:
            pass
    return False


def GetNewIconsDirName():
    return "%s%f" % (GetIconDirBaseName(), float(time()))


def CheckIconsDirName(path):
    dirName = GetLastDirNameFromPath(path)
    baseName = GetIconDirBaseName()
    if dirName.startswith(baseName):
        try:
            test = float(dirName[len(baseName):])
            return True
        except Exception:
            pass
    return False


def GetIconsDirs(basePath):
    iconsDirs = []
    try:
        list = os.listdir(basePath)
        for item in list:
            currPath = os.path.join(basePath, item)
            if os.path.isdir(currPath) and not os.path.islink(currPath) and CheckIconsDirName(item):
                iconsDirs.append(item)
    except Exception:
        printExc()
    return iconsDirs


def GetIconsFilesFromDir(basePath):
    iconsFiles = []
    if CheckIconsDirName(basePath):
        try:
            list = os.listdir(basePath)
            for item in list:
                currPath = os.path.join(basePath, item)
                if os.path.isfile(currPath) and not os.path.islink(currPath) and CheckIconName(item):
                    iconsFiles.append(item)
        except Exception:
            printExc()

    return iconsFiles


def GetCreationIconsDirTime(fullPath):
    try:
        dirName = GetLastDirNameFromPath(fullPath)
        baseName = GetIconDirBaseName()
        return float(dirName[len(baseName):])
    except Exception:
        return None


def GetCreateIconsDirDeltaDateInDays(fullPath):
    ret = -1
    createTime = GetCreationIconsDirTime(fullPath)
    if None is not createTime:
        try:
            currTime = datetime.datetime.now()
            modTime = datetime.datetime.fromtimestamp(createTime)
            deltaTime = currTime - modTime
            ret = deltaTime.days
        except Exception:
            printExc()
    return ret


def RemoveIconsDirByPath(path):
    printDBG("RemoveIconsDirByPath[%s]" % path)
    RemoveAllFilesIconsFromPath(path)
    try:
        os.rmdir(path)
    except Exception:
        printExc('RemoveIconsDirByPath dir[%s] is not empty' % path)


def RemoveOldDirsIcons(path, deltaInDays='7'):
    deltaInDays = int(deltaInDays)
    try:
        iconsDirs = GetIconsDirs(path)
        for item in iconsDirs:
            currDir = os.path.join(path, item)
            delta = GetCreateIconsDirDeltaDateInDays(currDir)  # we will check only directory date
            if delta >= 0 and deltaInDays >= 0 and delta >= deltaInDays:
                RemoveIconsDirByPath(currDir)
    except Exception:
        printExc()


def RemoveAllFilesIconsFromPath(path):
    printDBG("RemoveAllFilesIconsFromPath")
    try:
        list = os.listdir(path)
        for item in list:
            filePath = os.path.join(path, item)
            if CheckIconName(item) and os.path.isfile(filePath):
                printDBG('RemoveAllFilesIconsFromPath img: ' + filePath)
                try:
                    os.remove(filePath)
                except Exception:
                    printDBG("ERROR while removing file %s" % filePath)
    except Exception:
        printExc('ERROR: in RemoveAllFilesIconsFromPath')


def RemoveAllDirsIconsFromPath(path, old=False):
    if old:
        RemoveAllFilesIconsFromPath(path)
    else:
        try:
            iconsDirs = GetIconsDirs(path)
            for item in iconsDirs:
                currDir = os.path.join(path, item)
                RemoveIconsDirByPath(currDir)
        except Exception:
            printExc()


def formatBytes(bytes, precision=2):
    import math
    units = ['B', 'KB', 'MB', 'GB', 'TB']
    bytes = max(bytes, 0)
    if bytes:
        pow = math.log(bytes)
    else:
        pow = 0
    pow = math.floor(pow / math.log(1024))
    pow = min(pow, len(units) - 1)
    bytes /= math.pow(1024, pow)
    return ("%s%s" % (str(round(bytes, precision)), units[int(pow)]))


def remove_html_markup(s, replacement=''):
    tag = False
    quote = False
    out = ""
    for c in s:
        if c == '<' and not quote:
            tag = True
        elif c == '>' and not quote:
            tag = False
            out += replacement
        elif (c == '"' or c == "'") and tag:
            quote = not quote
        elif not tag:
            out = out + c
    return re.sub(r'&\w+;', ' ', out)


class CSearchHistoryHelper():
    TYPE_SEP = '|--TYPE--|'

    def __init__(self, name, storeTypes=False):
        self.length = None
        printDBG('CSearchHistoryHelper.__init__')
        self.storeTypes = storeTypes
        try:
            printDBG('CSearchHistoryHelper.__init__ name = "%s"' % name)
            self.PATH_FILE = GetSearchHistoryDir(name + ".txt")
        except Exception:
            printExc('CSearchHistoryHelper.__init__ EXCEPTION')

    def doRemove(self):
        printDBG('CSearchHistoryHelper.doRemove file = "%s"' % self.PATH_FILE)
        self.length = 0
        msg = 1, _('Unable to comply. Search History is empty.')
        try:
            if os.path.isfile(self.PATH_FILE):
                os.remove(self.PATH_FILE)
                msg = 0, _('Search History successfully deleted.')
        except:
            pass
        return msg

    def getLength(self):
        if self.length is None:
            self.length = 0
            if os.path.isfile(self.PATH_FILE):
                try:
                    num = 0
                    file = codecs.open(GetSearchHistoryDir("ytlist.txt"), 'r', 'utf-8', 'ignore')
                    for line in file:
                        num = num + 1
                    file.close()
                    self.length = num
                except:
                    pass

        if self.length:
            return _("Number of items in search history: %d") % self.length
        else:
            return _("Search History is empty.")

    def getHistoryList(self):
        printDBG('CSearchHistoryHelper.getHistoryList from file = "%s"' % self.PATH_FILE)
        historyList = []

        if os.path.isfile(self.PATH_FILE):
            try:
                file = codecs.open(self.PATH_FILE, 'r', 'utf-8', 'ignore')
                for line in file:
                    value = line.replace('\n', '').strip()
                    if len(value) > 0:
                        try:
                            historyList.insert(0, ensure_str(value))
                        except Exception:
                            printExc()
                file.close()
            except Exception:
                printExc()
                return []
        else:
            return []

        orgLen = len(historyList)
        # remove duplicates
        # last 50 searches patterns are stored
        historyList = historyList[:config.plugins.iptvplayer.search_history_size.value]
        uniqHistoryList = []
        for i in historyList:
            if i not in uniqHistoryList:
                uniqHistoryList.append(i)
        historyList = uniqHistoryList

        # strip file if it has to big overhead
        if orgLen - len(historyList) > 50:
            self._saveHistoryList(historyList)

        # now type also can be stored
        #################################
        newList = []
        for histItem in historyList:
            fields = histItem.split(self.TYPE_SEP)
            if 2 == len(fields):
                newList.append({'pattern': fields[0], 'type': fields[1]})
            elif self.storeTypes:
                newList.append({'pattern': fields[0]})

        if len(newList) > 0:
            return newList
        #################################

        return historyList

    def addHistoryItem(self, itemValue, itemType=None):
        printDBG('CSearchHistoryHelper.addHistoryItem to file = "%s"' % self.PATH_FILE)
        try:
            if config.plugins.iptvplayer.search_history_size.value > 0:
                file = codecs.open(self.PATH_FILE, 'a', 'utf-8', 'replace')
                value = itemValue
                if None is not itemType:
                    value = value + self.TYPE_SEP + itemType
                # value = value if type('') == type(value) else value.decode('utf-8', 'replace')
                file.write(value + '\n')
                printDBG('Added pattern: "%s"' % itemValue)
                file.close
                if self.length is None:
                    self.length = 0
                self.length += 1
        except Exception:
            printExc('CSearchHistoryHelper.addHistoryItem EXCEPTION')

    def _saveHistoryList(self, list):
        printDBG('CSearchHistoryHelper._saveHistoryList to file = "%s"' % self.PATH_FILE)
        try:
            l = len(list)
            with open(self.PATH_FILE, 'w', encoding="UTF-8") as fd:
                for i in range(l):
                    fd.write(list[l - 1 - i] + '\n')
            self.length = l
        except Exception:
            printExc('CSearchHistoryHelper._saveHistoryList EXCEPTION')

    @staticmethod
    def saveLastPattern(pattern):
        filePath = GetSearchHistoryDir("pattern")
        return WriteTextFile(filePath, pattern.replace('\n', '').replace('\r', ''))

    @staticmethod
    def loadLastPattern():
        filePath = GetSearchHistoryDir("pattern")
        if os.path.isdir(filePath):
            try:
                os.rmdir(filePath)
            except Exception:
                printExc('CSearchHistoryHelper.loadLastPattern EXCEPTION')
        return ReadTextFile(filePath)
# end CSearchHistoryHelper


def ReadTextFile(filePath, encode='utf-8', errors='ignore'):
    sts, ret = False, ''
    if os.path.isfile(filePath):
        try:
            file = codecs.open(filePath, 'r', encode, errors)
            ret = file.read().encode(encode, errors)
            file.close()
            if ret.startswith(codecs.BOM_UTF8):
                ret = ret[3:]
            sts = True
            ret = strDecode(ret, errors)
        except Exception:
            if 'SearchHistory/' in filePath:
                printExc('WARNING')
            else:
                printExc()

    return sts, ret


def WriteTextFile(filePath, text, encode='utf-8', errors='ignore'):
    sts = False
    try:
        toSave = text  # if type('') == type(text) else text.decode('utf-8', errors)
        file = codecs.open(filePath, 'w', encode, errors)
        file.write(toSave)
        file.close()
        sts = True
    except Exception:
        printExc()
    return sts


class CFakeMoviePlayerOption():
    def __init__(self, value, text):
        self.value = value
        self.text = text

    def getText(self):
        return self.text


class CMoviePlayerPerHost():
    def __init__(self, hostName):
        self.filePath = GetCacheSubDir('MoviePlayer', hostName + '.json')
        self.activePlayer = {}  # {buffering:True/False, 'player':''}
        self.load()

    def __del__(self):
        self.save()

    def load(self):
        from Plugins.Extensions.IPTVPlayer.libs.e2ijson import loads as json_loads
        sts, ret = False, ''
        try:
            if not os.path.isfile(self.filePath):
                sts = True
            else:
                file = codecs.open(self.filePath, 'r', 'utf-8', 'ignore')
                ret = ensure_str(file.read(), encoding='utf-8', errors='ignore')
                file.close()
                activePlayer = {}
                ret = json_loads(ret)
                activePlayer['buffering'] = ret['buffering']
                activePlayer['player'] = CFakeMoviePlayerOption(ret['player']['value'], ret['player']['text'])
                self.activePlayer = activePlayer
                sts = True
        except Exception:
            printExc()
        return sts, ret

    def save(self):
        from Plugins.Extensions.IPTVPlayer.libs.e2ijson import dumps as json_dumps
        sts = False
        try:
            if {} == self.activePlayer and os.path.isfile(self.filePath):
                os.remove(self.filePath)
            elif self.activePlayer.get('buffering', None) is None:
                printDBG('WARNING: buffering NOT set')
            else:
                data = {}
                data['buffering'] = self.activePlayer['buffering']
                data['player'] = {'value': self.activePlayer['player'].value, 'text': self.activePlayer['player'].getText()}
                data = json_dumps(ensure_str(data))
                file = codecs.open(self.filePath, 'w', 'utf-8', 'replace')
                file.write(data)
                file.close
                sts = True
        except Exception:
            printExc()
        return sts

    def get(self, key, defval):
        return self.activePlayer.get(key, defval)

    def set(self, activePlayer):
        self.activePlayer = activePlayer
        self.save()


def byteify(input, noneReplacement=None, baseTypesAsString=False):
    """
    if isinstance(input, dict):
        return dict([(byteify(key, noneReplacement, baseTypesAsString), byteify(value, noneReplacement, baseTypesAsString)) for key, value in input.items()])
    elif isinstance(input, list):
        return [byteify(element, noneReplacement, baseTypesAsString) for element in input]
    elif isinstance(input, str):
        return input.encode('utf-8')
    elif input == None and noneReplacement != None:
        return noneReplacement
    elif baseTypesAsString:
        return str(input)
    else:
    """
    return input


LASTExcMSG = ''


def clearExcMSG():
    global LASTExcMSG
    LASTExcMSG = ''


def getExcMSG(clearExcMSG=True):
    global LASTExcMSG
    retMSG = LASTExcMSG
    if clearExcMSG:
        LASTExcMSG = ''
    return retMSG


def printExc(msg='', WarnOnly=False):
    global LASTExcMSG
    isWarning = False
    printDBG("===============================================")
    if WarnOnly:
        printDBG("                    WARNING")
        isWarning = True
    elif msg.startswith('WARNING'):
        printDBG("                    WARNING")
        msg = msg[7:]
        isWarning = True
    elif msg.startswith('EXCEPTION'):
        printDBG("                    EXCEPTION")
        msg = msg[9:]
    else:
        printDBG("                   EXCEPTION")
    printDBG("===============================================")
    exc_formatted = traceback.format_exc()
    if msg == '' or msg == 'WARNING':
        msg = '\n%s' % exc_formatted
    else:
        msg = msg + ': \n%s' % exc_formatted
    printDBG(msg)
    printDBG("===============================================")
    try:
        retMSG = exc_formatted.splitlines()[-1]
    except Exception:
        retMSG = ''
    if not isWarning:
        LASTExcMSG = retMSG
    return retMSG  # returns the error description to possibly use in main code. E.g. inform about failed login


def GetIPTVPlayerVersion():
    try:
        from Plugins.Extensions.IPTVPlayer.version import IPTV_VERSION
    except Exception:
        IPTV_VERSION = "XX.YY.ZZ"
    return IPTV_VERSION


def GetIPTVPlayerComitStamp():
    try:
        from Plugins.Extensions.IPTVPlayer.version import COMMIT_STAMP
    except Exception:
        COMMIT_STAMP = ""
    return COMMIT_STAMP


def GetShortPythonVersion():
    return "%d.%d" % (sys.version_info[0], sys.version_info[1])


def GetVersionNum(ver):
    if ver == '':
        return 0
    try:
        if None is re.match(r"[0-9]+\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]", ver):
            raise Exception("Wrong version!")
        return int(ver.replace('.', ''))
    except Exception:
        printExc('Version[%r]' % ver)
        return 0


def IsFPUAvailable():
    try:
        if None is IsFPUAvailable.available:
            with open('/proc/cpuinfo', 'r') as f:
                data = f.read().strip().upper()
            if ' FPU ' in data:
                IsFPUAvailable.available = True
            else:
                IsFPUAvailable.available = False
        if IsFPUAvailable.available is False and config.plugins.iptvplayer.plarformfpuabi.value == 'hard_float':
            return True
    except Exception:
        printExc()
    return IsFPUAvailable.available


IsFPUAvailable.available = None


def IsSubtitlesParserExtensionCanBeUsed():
    try:
        if config.plugins.iptvplayer.useSubtitlesParserExtension.value:
            from Plugins.Extensions.IPTVPlayer.libs.iptvsubparser import _subparser as subparser
            if '' != subparser.version():
                printDBG('Subtitles Parser Extension available')
                return True
    except Exception:
        printExc('WARNING - Subtitles Parser Extension NOT available')
    return False


def IsBrokenDriver(filePath):
    # workaround for broken DVB driver mbtwinplus:
    # root@mbtwinplus:~# cat /proc/stb/video/policy2
    # Segmentation fault
    try:
        if 'video/policy' in filePath and not fileExists('/proc/stb/video/aspect_choices'):
            with open('/etc/hostname', 'r') as f:
                data = f.read().strip()
            if 'mbtwinplus' in data:
                return True
    except Exception:
        printExc()
    return False


def GetE2OptionsFromFile(filePath):
    options = []
    if IsBrokenDriver(filePath):
        return []
    try:
        if fileExists(filePath):
            with open(filePath, 'r') as f:
                data = f.read().strip()
                data = data.split(' ')
                for item in data:
                    opt = item.strip()
                    if '' != opt:
                        options.append(opt)
        else:
            printDBG('GetE2OptionsFromFile file[%s] not exists' % filePath)
    except Exception:
        printExc()
    return options


def SetE2OptionByFile(filePath, value):
    if IsBrokenDriver(filePath):
        return False
    sts = False
    try:
        with open(filePath, 'w') as f:
            data = f.write(value)
            sts = True
    except Exception:
        printExc()
    return sts


def GetE2VideoAspectChoices():
    tab = GetE2OptionsFromFile('/proc/stb/video/aspect_choices')
    # workaround for some STB
    # reported here: https://gitlab.com/iptvplayer-for-e2/iptvplayer-for-e2/issues/30
    staticTab = ["4:3", "16:9", "any"]
    if len(tab) < 2 and GetE2VideoAspect() in staticTab:
        tab = staticTab
    return tab


def GetE2VideoAspect():
    options = GetE2OptionsFromFile('/proc/stb/video/aspect')
    if 1 == len(options):
        return options[0]
    return None


def SetE2VideoAspect(value):
    return SetE2OptionByFile('/proc/stb/video/aspect', value)


def GetE2VideoPolicyChoices(num=''):
    return GetE2OptionsFromFile('/proc/stb/video/policy%s_choices' % num)


def GetE2VideoPolicy(num=''):
    options = GetE2OptionsFromFile('/proc/stb/video/policy' + num)
    if 1 == len(options):
        return options[0]
    return None


def SetE2VideoPolicy(value, num=''):
    return SetE2OptionByFile('/proc/stb/video/policy' + num, value)


def GetE2AudioCodecMixChoices(codec):
    return GetE2OptionsFromFile('/proc/stb/audio/%s_choices' % codec)


def GetE2AudioCodecMixOption(codec):
    options = GetE2OptionsFromFile('/proc/stb/audio/%s' % codec)
    if 1 == len(options):
        return options[0]
    return None


def SetE2AudioCodecMixOption(codec, value):
    return SetE2OptionByFile('/proc/stb/audio/%s' % codec, value)

# videomode


def GetE2VideoModeChoices():
    # return 'pal ntsc 480i 576i 480p 576p 720p50 720p 1080i50 1080i 1080p24 1080p25 1080p30 720p24 720p25 720p30 1080p50 1080p'.split(' ')
    return GetE2OptionsFromFile('/proc/stb/video/videomode_choices')


def GetE2VideoMode():
    # return '1080p50'
    options = GetE2OptionsFromFile('/proc/stb/video/videomode')
    if 1 == len(options):
        return options[0]
    return None


def SetE2VideoMode(value):
    return SetE2OptionByFile('/proc/stb/video/videomode', value)


def ReadUint16(tmp, le=True):
    if le:
        return tmp[1] << 8 | tmp[0]
    else:
        return tmp[0] << 8 | tmp[1]


def ReadUint32(tmp, le=True):
    if le:
        return tmp[3] << 24 | tmp[2] << 16 | tmp[1] << 8 | tmp[0]
    else:
        return tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]


def ReadGnuMIPSABIFP(elfFileName):
    SHT_GNU_ATTRIBUTES = 0x6ffffff5
    SHT_MIPS_ABIFLAGS = 0x7000002a
    Tag_GNU_MIPS_ABI_FP = 4
    Val_GNU_MIPS_ABI_FP_ANY = 0
    Val_GNU_MIPS_ABI_FP_DOUBLE = 1
    Val_GNU_MIPS_ABI_FP_SINGLE = 2
    Val_GNU_MIPS_ABI_FP_SOFT = 3
    Val_GNU_MIPS_ABI_FP_OLD_64 = 4
    Val_GNU_MIPS_ABI_FP_XX = 5
    Val_GNU_MIPS_ABI_FP_64 = 6
    Val_GNU_MIPS_ABI_FP_64A = 7
    Val_GNU_MIPS_ABI_FP_NAN2008 = 8

    def _readLeb128(data, start, end):
        result = 0
        numRead = 0
        shift = 0
        byte = 0

        while start < end:
            byte = data[start]
            numRead += 1

            result |= (byte & 0x7f) << shift

            shift += 7
            if byte < 0x80:
                break
        return numRead, result

    def _getStr(stsTable, idx):
        val = ''
        while stsTable[idx] != '\0':
            val += stsTable[idx]
            idx += 1
        return val

    Val_HAS_MIPS_ABI_FLAGS = False
    Val_GNU_MIPS_ABI_FP = -1
    try:
        with open(elfFileName, "rb") as file:
            # e_shoff - Start of section headers
            file.seek(32)
            shoff = ReadUint32(file.read(4))

            # e_shentsize - Size of section headers
            file.seek(46)
            shentsize = ReadUint16(file.read(2))

            # e_shnum -  Number of section headers
            shnum = ReadUint16(file.read(2))

            # e_shstrndx - Section header string table index
            shstrndx = ReadUint16(file.read(2))

            # read .shstrtab section header
            headerOffset = shoff + shstrndx * shentsize

            file.seek(headerOffset + 16)
            offset = ReadUint32(file.read(4))
            size = ReadUint32(file.read(4))

            file.seek(offset)
            secNameStrTable = file.read(size)

            for idx in range(shnum):
                offset = shoff + idx * shentsize
                file.seek(offset)
                sh_name = ReadUint32(file.read(4))
                sh_type = ReadUint32(file.read(4))
                if sh_type == SHT_GNU_ATTRIBUTES:
                    file.seek(offset + 16)
                    sh_offset = ReadUint32(file.read(4))
                    sh_size = ReadUint32(file.read(4))
                    file.seek(sh_offset)
                    contents = file.read(sh_size)
                    p = 0
                    if contents.startswith('A'):
                        p += 1
                        sectionLen = sh_size - 1
                        while sectionLen > 0:
                            attrLen = ReadUint32(contents[p:])
                            p += 4

                            if attrLen > sectionLen:
                                attrLen = sectionLen
                            elif attrLen < 5:
                                break
                            sectionLen -= attrLen
                            attrLen -= 4
                            attrName = _getStr(contents, p)

                            p += len(attrName) + 1
                            attrLen -= len(attrName) + 1

                            while attrLen > 0 and p < len(contents):
                                if attrLen < 6:
                                    sectionLen = 0
                                    break
                                tag = contents[p]
                                p += 1
                                size = ReadUint32(contents[p:])
                                if size > attrLen:
                                    size = attrLen
                                if size < 6:
                                    sectionLen = 0
                                    break

                                attrLen -= size
                                end = p + size - 1
                                p += 4

                                if tag == 1 and attrName == "gnu":  # File Attributes
                                    while p < end:
                                        # display_gnu_attribute
                                        numRead, tag = _readLeb128(contents, p, end)
                                        p += numRead
                                        if tag == Tag_GNU_MIPS_ABI_FP:
                                            numRead, val = _readLeb128(contents, p, end)
                                            p += numRead
                                            Val_GNU_MIPS_ABI_FP = val
                                            break
                                elif p < end:
                                    p = end
                                else:
                                    attrLen = 0
                elif sh_type == SHT_MIPS_ABIFLAGS:
                    Val_HAS_MIPS_ABI_FLAGS = True
    except Exception:
        printExc()
    return Val_HAS_MIPS_ABI_FLAGS, Val_GNU_MIPS_ABI_FP


def MergeDicts(*dict_args):
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result


def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(0)
    try:
        s.connect(('8.8.8.8', 80))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP


def is_port_in_use(pIP, pPORT):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    res = sock.connect_ex((pIP, pPORT))
    sock.close()
    return res == 0


def hasCDM():
    try:
        from pywidevinecdm.checkCDMvalidity import testDevice
        return testDevice()
    except Exception:
        return False


def readCFG(cfgName, defVal=''):
    for myPath in ['/etc/enigma2/IPTVplayer_defaults/', '/hdd/IPTVplayer_defaults/']:
        if os.path.exists(myPath):
            cfgPath = os.path.join(myPath, cfgName)
            if os.path.exists(cfgPath):
                retVal = open(cfgPath, 'r').readline().strip()
                if retVal == 'True':
                    retVal = True
                elif retVal == 'False':
                    retVal = False
                return retVal
            else:
                with open('/etc/enigma2/settings', 'r') as f:
                    for line in f:
                        line = line.strip()
                        if line.startswith('config.plugins.iptvplayer.%s=' % cfgName):
                            defVal = line.split('=')[1]
                            open(cfgPath, 'w').write(defVal)
    return defVal


def checkWebSiteStatus(URL, HEADERS=None, TIMEOUT=1):
    global LASTExcMSG
    if HEADERS is None:
        HEADERS = {
            'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:88.0) Gecko/20100101 Firefox/88.0',
            'Accept-Charset': 'utf-8',
            'Content-Type': 'text/html; charset=utf-8'
    }
    req = urllib2_Request(URL, headers=HEADERS)
    try:
        response = urllib2_urlopen(req, timeout=TIMEOUT)
    except urllib2_HTTPError as e:
        LASTExcMSG = str(e)
        return (False, "Website returned error", str(e.code))
    except urllib2_URLError as e:
        LASTExcMSG = str(e)
        return (False, 'Website NOT available', str(e.reason))
    except socket.timeout as e:
        LASTExcMSG = str(e)
        return (False, 'Website overloaded and dont respond timely', str('Timeout %ss' % TIMEOUT))
    except Exception as e:
        LASTExcMSG = str(e)
        return (False, 'EXCEPTION', str(e))
    else:
        return (True, '', None)


def E2ColoR(color):
    COLORS_DEFINITIONS = {
        "black": "\\c00000000",
        "silver": "\\c00C0C0C0",
        "gray": "\\c00808080",
        "white": "\\c00FFFFFF",
        "maroon": "\\c00800000",
        "red": "\\c00FA8072",  # Soft red
        "purple": "\\c00800080",
        "fuchsia": "\\c00FF00FF",
        "aqua": "\\c0000FFFF",
        "teal": "\\c00008080",
        "blue": "\\c000000FF",
        "green": "\\c00008000",
        "lime": "\\c0030FF30",  # Vivid lime green
        "olive": "\\c00808000",
        "yellow": "\\c00FFFF30",  # Vivid yellow
        "navy": "\\c00000080",  # Dark blue
        "violet": "\\c00EE82EE",
        "dodgerblue": "\\c001E90FF",
        "lightcoral": "\\c00F08080",
        "lightred": "\\c00FF7950",
        "gold": "\\c00FFD700",
        "orange": "\\c00FFA500",
        "skyblue": "\\c0087CEEB",
        "coral": "\\c00FF7F50",
        "khaki": "\\c00F0E68C",
        "crimson": "\\c00DC143C",
        "cyan": "\\c0000FFFF"
    }
    try:
        return COLORS_DEFINITIONS.get(color, '') if config.plugins.iptvplayer.use_colors.value else ''
    except AttributeError:
        return ''
